#include <gion/auto_array.hpp>

#include <cassert>
#include <cstddef>

using gion::auto_array;

struct Base
{
  static std::size_t n;
  Base()
  {
    ++n;
  }
  Base(const Base&)
  {
    ++n;
  }
  virtual ~Base()
  {
    --n;
  }
};

struct Derived : Base
{};

std::size_t Base::n = 0;

void basic_tests()
{
  assert(Base::n == 0);

  auto_array<Base> bar(new Base [10]);
  assert(Base::n == 10);
  assert(bar.get() != 0);

  Base* p = bar.release();
  assert(Base::n == 10);
  assert(bar.get() == 0);

  bar.reset(p);
  assert(Base::n == 10);
  assert(bar.get() != 0);
  
  bar.reset();
  assert(Base::n == 0);
  assert(bar.get() == 0);

}
void subscription_tests()
{
  size_t x[] = {0, 1, 2, 3};
  auto_array<size_t> baz(x);
  for(size_t i = 0; i < sizeof(x) / sizeof(x[0]); ++i)
  {
    assert(baz[i] == i);
  }
  baz.release();
}

auto_array<Base> producer()
{
  return auto_array<Base>(new Base [1]);
}

void consumer(auto_array<Base> bar)
{
  assert(bar.get() != 0);
}
void ownership_transfer_tests()
{
  assert(Base::n == 0);
  {
    consumer(producer());
    assert(Base::n == 0);
    auto_array<Base> bar;
    bar = producer();
    assert(bar.get() != 0);
    assert(Base::n == 1);
    auto_array<Base> baz(producer());
    assert(baz.get() != 0);
    assert(Base::n == 2);
    bar = baz;
    assert(baz.get() == 0);
    assert(Base::n == 1);
    producer();
    assert(Base::n == 1);
  }
  assert(Base::n == 0);
}

void polymorphism_tests()
{
  auto_array<Derived> foo;
  auto_array<Base> bar(foo);
  bar = foo;
}

int main()
{
  basic_tests();
  ownership_transfer_tests();
  subscription_tests();
  polymorphism_tests();
  return 0;
}
